package common;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

public class Round extends Updating implements Sendable {
	private static final long serialVersionUID = -1415676007374747135L;
	
	private static AtomicInteger instanceCount = new AtomicInteger(0);
	private int uniqueID;
	
	private volatile PhaseEnum phase = PhaseEnum.REGISTRATION;
	private List<Player> players;
	
	private long roundStart;
	private long phaseStart;
	
	public Round() {
		
		roundStart = System.currentTimeMillis();
		phaseStart = roundStart;
		
		players = new Vector<Player>();
		uniqueID = instanceCount.addAndGet(1);
	}
	
	// Should be called by server
	public void changePhase() {
		phase = phase.nextPhase();
		phaseStart = System.currentTimeMillis();
		
		if( phase == PhaseEnum.TRADING )
			initializePlayerLimits();
	}
	
	private void initializePlayerLimits() {
		
		Random r = new Random();
		
		for( Commodity commodity : Commodity.values() ) {
			
			int numBuyers = (int) Math.floor( players.size() / 2 );
			int numSellers = players.size() - numBuyers;
			
			double minSell = commodity.quality * Math.abs(r.nextInt()) % 1000;
			double maxBid = commodity.quality * minSell + Math.abs(r.nextInt()) % 1000;
			
			int quotaTotal = numBuyers * numSellers * ( Math.abs(r.nextInt()) % 1000 + 100 );
			int QB = quotaTotal / numBuyers;
			int QS = quotaTotal / numSellers;
			
			CommodityLimits seller = new CommodityLimits(false, QS, minSell);
			CommodityLimits buyer = new CommodityLimits(true, QB, maxBid );
			
			for(int i = 0; i < players.size(); ++i ) {
				PlayerLimits limits = players.get(i).getLimits();
				
				if( limits == null )
					limits = new PlayerLimits(false);
				
				if( numBuyers == 0 || numSellers == 0) {
					//If either the number of sellers or buyers reaches zero, all remaining players are the other type.
					if( numBuyers == 0) {
						limits.put( commodity, seller );
						--numSellers;
					} else {
						limits.put( commodity, buyer );
						--numBuyers;
					}
					
					
				} else if( r.nextBoolean() ) {
					//randomly make them a seller
					--numSellers;
					
					limits.put(commodity, seller);
				} else {
					//randomly make them a buyer
					--numBuyers;
					
					limits.put(commodity, buyer);
				}
				
				players.get( i ).setLimits( limits );
			}
			
		}
	}
	
	public long getRoundStart() {
		return roundStart;
	}
	
	public long getPhaseStart() {
		return phaseStart;
	}
	
	public void restartPhase() {
		phaseStart = System.currentTimeMillis();
	}
	
	public PhaseEnum getCurrentPhase() {
		return phase;
	}
	
	public boolean canRegister() {
		return phase == PhaseEnum.REGISTRATION;
	}
	
	public boolean addPlayer (Player name) {
		if( phase == PhaseEnum.REGISTRATION ) {
			players.add(name);
			name.setRound(this);
			return true;
		}
		
		return false;
	}
	
	public boolean removePlayer (Player name) {
		if( phase == PhaseEnum.REGISTRATION ) {
			players.remove(name);
			name.setRound( null );
			return true;
		}
		
		return false;
	}
	
	public int numberOfPlayers() { 
		return players.size();
	}
	
	public List<Player> getPlayers() {
		return players;
	}
	
	public String getType() {
		return "Round";
	}

	public void update( Round r ) {
		players = r.players;
		phase = r.phase;
		this.setUpdated();
	}
	
	public boolean equals (Round r) {
		return uniqueID == r.uniqueID;
	}
	
	public int getID () { 
		return uniqueID;
	}
	
	public String toString() { 
		return "Round #" + uniqueID + " (" + phase+")\nPlayers :" + players.toString(); 
	}
}
